/**
 * @file ngdefaultmessagecoder.cpp
 * @author Suk Robert Koh (srkoh87z@gmail.com)
 */

#include "ngine/common/message/ngdefaultmessagecoder.h"
#include <stdio.h>

/**
 * Default constructor for NGDefaultMessageCoder class
 */
NGDefaultMessageCoder::NGDefaultMessageCoder()
: NGMessageCoder((BYTE) 0x87, (BYTE) 0x91, (BYTE) 4, (BYTE) 1, FALSE)
{

}

/**
 * Destructor for NGDefaultMessageCoder class
 */
NGDefaultMessageCoder::~NGDefaultMessageCoder()
{

}

/**
 * Encodes NGMessage type to string
 *
 * @param	NGMessage *		Pointer to a message object
 * @return	char *			Pointer to a encoded string
 */
char *NGDefaultMessageCoder::encode(NGMessage *msg)
{
	// allocate space to store encoded string
	char *buffer = (char *) malloc((int) (msg->getLength() + headerSize + 2));

	// get type and length of the data
	BYTE type = msg->getType();
	WORD length = ~msg->getLength();

	// set the data
	memset(buffer, 0, (int) msg->getLength() + headerSize + 2);
	memcpy(buffer, (char *) &frontCode, 1);
	memcpy(buffer + 1, (char *) &type, 1);
	memcpy(buffer + 2, (char *) &length, 2);
	memcpy(buffer + 4, msg->getData(), (int) msg->getLength());
	memcpy(buffer + 4 + msg->getLength(), (char *) &endCode, 1);

	return buffer;
}

/**
 * Decodes string to NGMessageType
 *
 * @param	const char *	Pointer to a string
 * @return	NGMessage *		Pointer to decoded message object
 */
NGMessage *NGDefaultMessageCoder::decode(const char *messageData, DWORD userId)
{
	NGMessage *message = new NGMessage();

	// extract header
	char header[headerSize + 1];
	memset(header, 0, headerSize + 1);
	memcpy(header, messageData, headerSize);

	// validate
	if((BYTE) header[0] != frontCode)
		return NULL;
	if((BYTE) messageData[strlen(messageData) - 1] != endCode)
		return NULL;

	// fill in message information
	message->setType(header[1]);
	message->setSenderId(userId);
	message->setData(extractData(messageData, getMessageLength(header)));

	return message;
}

/**
 * Gets the message length
 *
 * @param	const char *	Pointer to a header
 * @return	WORD			Length of the message
 */
WORD NGDefaultMessageCoder::getMessageLength(const char *header)
{
	int length = 0;

	memcpy((char *) &length, header + 2, 2);

	// invert bits to avoid empty byte within string
	return ~length;
}

/**
 * Gets the data of the message
 *
 * @param	const char *		Pointer to a encoded string
 * @param	int					Length of the message
 * @return	char *				Pointer to the data of the message
 */
char *NGDefaultMessageCoder::extractData(const char *messageData, int length)
{
	// allocate space
	char *data = (char *) malloc(sizeof(char) * length + 1);

	// copy data
	memcpy(data, messageData + headerSize, length);
	data[length] = '\0';

	return data;
}
